package com.boboPlanet.comm.component;

import com.boboPlanet.comm.utils.DateUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.Objects;

/**
 * @Description: TODO jwt接口鉴权配置
 * @Author: mis_wu
 * @Date: 2023/5/8
 * @Company planet
 **/
@Slf4j
@Data
@Component
public class JwtConfig {

    @Resource
    private JwtProperties jwtProperties;

    /**
     * 生成token
     * @param subject 秘钥内容
     * @param expire 过期时间,unit/minute
     * @param unit 过期单位
     * @return 签名
     */
    public String createToken(String subject,Long expire,String unit) {
        //todo:秘钥，可读取properties中（当前），也可自定义生成 generateSecret();
        //设置过期时间
        setCustomExpireTime(expire,unit);
        if (StringUtils.isBlank(jwtProperties.getSecret())){
            log.error("createToken error,because secret is not null!!!");
            return StringUtils.EMPTY;
        }
        //过期时间 ms
        Date expireDate = new Date(System.currentTimeMillis() + jwtProperties.getExpiration());
        return Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .setSubject(subject)
                .setIssuedAt(new Date())
                .setExpiration(expireDate)
                .signWith(SignatureAlgorithm.HS512, jwtProperties.getSecret())
                .compact();
    }

    /**
     * 不使用properties秘钥，自定义生成秘钥
     */
    public void generateSecret(){
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(jwtProperties.getAlgorithm());
            keyGenerator.init(jwtProperties.getSignSize());
            SecretKey secretKey = keyGenerator.generateKey();
            byte[] encoded = secretKey.getEncoded();
            jwtProperties.setSecret(Base64.encodeBase64String(encoded));
        }catch (Exception e){
            log.error("generate authentication secret fail==>"+e.getMessage(),e);
            jwtProperties.setSecret(StringUtils.EMPTY);
        }
    }

    /**
     * 设置自定义失效时间,为空取配置时间
     * @param expire 过期时间 unit/minute
     * @param unit 单位
     */
    public void setCustomExpireTime(Long expire,String unit){
        if (expire == null || expire <= 0){
           expire = jwtProperties.getExpiration();
        }else {
            expire = DateUtil.timeConvertToMillis(expire,unit);
        }

        jwtProperties.setExpiration(expire);
    }

    /**
     * 获取token中注册信息
     * @param sign 签名
     * @return Claims
     */
    public Claims getTokenClaim (String sign) {
        try {
            return Jwts.parser().setSigningKey(jwtProperties.getSecret()).parseClaimsJws(sign).getBody();
        }catch (Exception e){
            log.error("getTokenClaim error ==>"+e.getMessage(),e);
            return null;
        }
    }
    /**
     * 验证token是否过期失效
     * @param sign 签名秘钥
     * @return true:没过期  false：过期
     */
    public boolean isTokenExpired (String sign) {
        if (StringUtils.isBlank(sign) || StringUtils.EMPTY.equals(sign)){
            return false;
        }
        Claims tokenClaim = getTokenClaim(sign);
        if (ObjectUtils.isEmpty(tokenClaim)){
            return false;
        }
        return tokenClaim.getExpiration().after(new Date());
    }

    /**
     * 获取token失效时间
     * @param sign 签名
     * @return Date
     */
    public Date getExpirationDateFromToken(String sign) {
        return Objects.requireNonNull(getTokenClaim(sign)).getExpiration();
    }

    /**
     * 从token中获取用户信息
     */
    public String getUsernameFromToken(String token) {
        return getTokenClaim(token).getSubject();
    }

    /**
     * 获取jwt发布时间
     */
    public Date getIssuedAtDateFromToken(String token) {
        return getTokenClaim(token).getIssuedAt();
    }

}
